﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;
using System.Text.Unicode;
using System.Threading.Tasks;

namespace Common
{
    /// <summary>
    /// JSON工具类
    /// </summary>
    public static class JsonHelper
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        static JsonHelper()
        {
            JsonSerializerOptions.Converters.Add(new DateTimeConverterUsingDateTimeParse());//日期格式转换器
        }

        /// <summary>
        /// JSON序列化的一些设置
        /// </summary>
        public static JsonSerializerOptions JsonSerializerOptions = new JsonSerializerOptions()
        {
            // 整齐打印
            WriteIndented = true,

            // 设置Json字符串支持的编码，默认情况下，序列化程序会转义所有非 ASCII 字符。 即，会将它们替换为 \uxxxx，其中 xxxx 为字符的 Unicode
            // 代码。 可以通过设置Encoder来让生成的josn字符串不转义指定的字符集而进行序列化 下面指定了基础拉丁字母和中日韩统一表意文字的基础Unicode 块
            // (U+4E00-U+9FCC)。 基本涵盖了除使用西里尔字母以外所有西方国家的文字和亚洲中日韩越的文字
            //Encoder = JavaScriptEncoder.Create(UnicodeRanges.BasicLatin, UnicodeRanges.CjkUnifiedIdeographs),

            //允许在反序列化 JSON 对象中的常规属性之后指定 JSON 元数据属性。
            //AllowOutOfOrderMetadataProperties = true,

            //不进行编码转换
            Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,

            // 忽略值为Null的属性
            //IgnoreNullValues = true,

            //获取或设置用于将 IDictionary 密钥名称转换为其他格式（如 camel 大小写）的策略。
            //DictionaryKeyPolicy =  JsonNamingPolicy.CamelCase,

            // 反序列化不区分大小写
            PropertyNameCaseInsensitive = true,
            // 驼峰命名
            //PropertyNamingPolicy = JsonNamingPolicy.CamelCase,

            // 对字典的键进行驼峰命名
            //DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,

            // 序列化的时候忽略null值属性
            //DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,

            // 忽略只读属性，因为只读属性只能序列化而不能反序列化，所以在以json为储存数据的介质的时候，序列化只读属性意义不大
            IgnoreReadOnlyFields = true,

            // 允许结尾有逗号的不标准json
            AllowTrailingCommas = true,

            // 允许有注释的不标准json
            ReadCommentHandling = JsonCommentHandling.Skip,

            // 允许在反序列化的时候原本应为数字的字符串（带引号的数字）转为数字
            NumberHandling = JsonNumberHandling.AllowReadingFromString,

            //获取一个 对象，该对象指示在序列化期间检测到引用周期时是否忽略对象。
            ReferenceHandler = ReferenceHandler.IgnoreCycles,

            // 处理循环引用类型，比如Book类里面有一个属性也是Book类
            //ReferenceHandler = ReferenceHandler.Preserve,

            //在序列化或反序列化时，使用 JsonSerializerOptions.IncludeFields 全局设置或 [JsonInclude] 特性来包含字段（必须是public），
            //当应用于某个属性时，指示非公共的 getter 和 setter 可用于序列化和反序列化。 不支持非公共属性。
            IncludeFields = true,

            TypeInfoResolver = new DefaultJsonTypeInfoResolver(),
        };

        /// <summary>
        /// 将字符串转换成动态JSON对象
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static dynamic ToDynamic(this string value)
        {
            return DynamicJson.Parse(value, JsonSerializerOptions);
        }

        /// <summary>
        /// 将字符串转换成指定类型的对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="value"></param>
        /// <returns></returns>
        public static T ToObject<T>(this string value)
        {
            return JsonSerializer.Deserialize<T>(value, JsonSerializerOptions);
        }

        public static JsonNodeOptions GetNodeOptions(JsonSerializerOptions options)
        {
            return options == null ? default : new JsonNodeOptions()
            {
                PropertyNameCaseInsensitive = options.PropertyNameCaseInsensitive,
            };
        }

        public static JsonDocumentOptions GetDocumentOptions(JsonSerializerOptions options)
        {
            return options == null ? default : new JsonDocumentOptions
            {
                AllowTrailingCommas = options.AllowTrailingCommas,
                CommentHandling = options.ReadCommentHandling,
                MaxDepth = options.MaxDepth
            };
        }

        /// <summary>
        /// 将对象转换成JSON字符串
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static string ToJsonString<T>(this T obj) where T : class
        {
            return JsonSerializer.Serialize(obj, JsonSerializerOptions);
        }

    }
}
